#include "socket.h"
//获取广播📢 socketId
const uint8 *local_ip = NULL;
const uint8 *local_ip_port = NULL;
void SCOKET_UDP_RADI(struct sockaddr_in *client_addr,
                     struct sockaddr_in *local_addr,
                     VlanData *vdata, int local_addr_len)
{
    LOG_DEBUG("init SCOKET_UDP_RADI");
    //网络相关配置
    local_addr->sin_family = AF_INET;
    local_addr->sin_port = htons(vdata->uparm.port);
    local_addr->sin_addr.s_addr = inet_addr(vdata->uparm.sourceIp);
    // local_addr->sin_port = htons(atoi(local_ip_port));
    // local_addr->sin_addr.s_addr = inet_addr(local_ip_port);          //本地网卡ip

    int socketId = socket(AF_INET, SOCK_DGRAM, 0);
    if (socketId < 0)
    {
        LOG_ERROR("#ERR: -[%s:%d]- socket failed ! socketId: %d ", vdata->uparm.sourceIp, vdata->uparm.port, socketId);
        LOG_ERROR("%d : %s",errno,strerror(errno));
        return;
    }
    int ret = bind(socketId, (struct sockaddr *)local_addr, local_addr_len);

    vdata->socketId = socketId;

    if (ret < 0)
    {
        vdata->flag = VD_FLAG_OFF;
        LOG_ERROR("#ERR: -[%s:%d]- err to bind socket, thread_id: %d, err code: %d ", vdata->uparm.sourceIp, vdata->uparm.port, vdata->thread_id, ret);
        LOG_ERROR("%d : %s",errno,strerror(errno));
        return;
    }
}
//获取组播📢 socketId
void SCOKET_UDP_MULT(struct ip_mreq *mreq, int mreq_len,
                     struct sockaddr_in *client_addr,
                     struct sockaddr_in *local_addr,
                     VlanData *vdata, int local_addr_len)
{
    LOG_DEBUG("init SCOKET_UDP_MULT");
    local_addr->sin_family = AF_INET;
    local_addr->sin_addr.s_addr = htonl(INADDR_ANY);
    local_addr->sin_port = htons(vdata->uparm.port);
    int socketId = socket(AF_INET, SOCK_DGRAM, 0);

    if (socketId < 0)
    {
        LOG_ERROR("#ERR: -[%s:%d]- socket failed ! socketId: %d ", vdata->uparm.sourceIp, vdata->uparm.port, socketId);
        LOG_ERROR("%d : %s",errno,strerror(errno));
        return;
    }
    int ret = bind(socketId, (struct sockaddr *)local_addr, local_addr_len);

    vdata->socketId = socketId;

    if (ret < 0)
    {
        vdata->flag = VD_FLAG_OFF;
        LOG_ERROR("#ERR: -[%s:%d]- err to bind socket, thread_id: %d, err code: %d ", vdata->uparm.sourceIp, vdata->uparm.port, vdata->thread_id, ret);
        LOG_ERROR("%d : %s",errno,strerror(errno));
        return;
    }

    mreq->imr_multiaddr.s_addr = inet_addr(vdata->uparm.sourceIp);
    // mreq->imr_interface.s_addr = htonl(INADDR_ANY);
    mreq->imr_interface.s_addr = inet_addr(local_ip);
    ret = setsockopt(socketId, IPPROTO_IP, IP_ADD_MEMBERSHIP, mreq, mreq_len);
    if (ret < 0)
    {
        LOG_ERROR("#ERR: -[%s:%d]- err to set sockopt failed ! ret: %d", vdata->uparm.sourceIp, vdata->uparm.port, ret);
        LOG_ERROR("%d : %s",errno,strerror(errno));
        return;
    }
}

/**
 * @brief 接收网络程序
 * @param vdata 
 */
extern pthread_mutex_t mutex;
extern pthread_cond_t has_producer;
extern uint8 net_buf[VALN_BUF_LEN];
extern int scan_flag;
void * recv_net_data(void *paraPtr) {
    VlanData *vdata = paraPtr;
    prctl(PR_SET_NAME, "UDP_RX");
    LOG_INFO("Net start..., ip: %s, port: %d ", vdata->uparm.sourceIp, vdata->uparm.port);
    // pthread_detach(pthread_self());   //设置分离

    //加入对应的组播
    struct sockaddr_in client_addr;
    struct sockaddr_in local_addr;

    vdata->client_addr = &client_addr;
    vdata->local_addr = &local_addr;

    struct ip_mreq mreq; // 多播地址结构体

    memset(&local_addr, 0, sizeof(local_addr));
    int blen = sizeof(local_addr);

    vdata->uparm.type == UDP_MULT
        ? SCOKET_UDP_MULT(&mreq, sizeof(mreq), &client_addr, &local_addr, vdata, blen)
        : SCOKET_UDP_RADI(&client_addr, &local_addr, vdata, blen);

    uint8 *rbuf = vdata->uparm.rbuf;
    uint32 rlen = sizeof(vdata->uparm.rbuf);
    LOG_INFO("socketId: %d, recv buff: %p, buff len: %d", vdata->socketId, rbuf, rlen);
    int qlen = 0;               // 返回的字节数
    while(1) {

#if     MODULE_TEST
        sleep(1);
        pthread_cond_signal(&has_producer);  //测试消费者
#endif // MODULE_TEST

        qlen = recvfrom(vdata->socketId, rbuf, rlen, 0, (struct sockaddr *)&client_addr, &blen);
        if(qlen < 0) {
            LOG_WARN("recv data error, data len is: %d, socketid: %d", qlen, vdata->socketId);
            LOG_ERROR("%d : %s",errno,strerror(errno));
        }
        if(qlen > sizeof(net_buf)) {
            LOG_ERROR("buff len is too lage");
            continue;
        }
        memset(net_buf, 0x0, sizeof(net_buf));
        memcpy(net_buf, rbuf, qlen);
        pthread_cond_signal(&has_producer);  //唤醒消费者线程
    }
}
VlanData * global_vdata;
void * recv_net_init() {
    LOG_INFO("init socket net ...");
    UdpParam pdata[VALN_NUM];
    pdata[0].flag = VD_FLAG_ON;
    pdata[0].port = atoi(local_ip_port);
    pdata[0].type = UDP_RADI;
    memset(pdata[0].sourceIp, 0x0, sizeof(pdata[0].sourceIp));
    memcpy(pdata[0].sourceIp, local_ip, strlen(local_ip));
    global_vdata = (VlanData *) malloc(VALN_NUM * sizeof(VlanData));
    VlanData * vdataPtr = global_vdata;
    int i = 0;
    for (i = 0; i < VALN_NUM; i++) {
        UdpParam *param = &pdata[i];
        vdataPtr->threadId = i;
        vdataPtr->flag = param->flag;
        memcpy(&vdataPtr->uparm, param, sizeof(UdpParam));
        LOG_INFO("udp ip: %s, udp port: %d", vdataPtr->uparm.sourceIp, vdataPtr->uparm.port);
        LOG_INFO("vdata: %p, udp status: %d, rbuf: %p", vdataPtr, vdataPtr->uparm.flag, vdataPtr->uparm.rbuf);
        if (vdataPtr->flag != VD_FLAG_OFF)
        {
            pthread_create(&vdataPtr->thread_id, NULL, recv_net_data, (VlanData *)vdataPtr);
        }
        *vdataPtr++;
    }
    return (void *)global_vdata;
}

void recv_net_end(void * para) {
    VlanData * vdataPtr = (VlanData *) para;
    LOG_INFO("destory socket net ...");
    int cnt = 0;
    for(; cnt < VALN_NUM; cnt++) {
        LOG_DEBUG("vdata: %p, udp ip: %s, udp port: %d, udp status: %d, rbuf: %p", vdataPtr, vdataPtr->uparm.sourceIp, vdataPtr->uparm.port, vdataPtr->uparm.flag, vdataPtr->uparm.rbuf);
        close(vdataPtr->socketId);
    }
    free(vdataPtr);
}

void send_net_data(uint8 *cbuf, int clen) {
    // 这里默认的是向第一个网络 socketid 发送数据
    int default_index = 0;
    VlanData * vdata = global_vdata + default_index * sizeof(VlanData);
    int res = sendto(vdata->socketId, cbuf, clen, 0, (struct sockaddr *)vdata->client_addr, sizeof(struct sockaddr));  

    // if(res != 0) {
    //     LOG_ERROR("#ERR: send network data failed, socketId: %d", vdata->socketId);
    //     LOG_ERROR("#ERR: error code: %d, errmsg: %s", errno, strerror(errno));
    // }  
    // LOG_DEBUG("send network data successful, socketId is %d", vdata->socketId);
}


